const path = require("path");
const fse = require('fs-extra');
const fs = require("fs").promises;
const {ip, environment, sendResponse, PORT} = require('../untils');

/**
 * 安全获取基础路径（处理开发/生产环境差异）
 */
const getBasePath = () => {
    const splitStr = environment === 'dev' ? '\\routes' : '/routes';
    return __dirname.split(splitStr)[0];
};

/**
 * 获取上传目录路径
 */
const getUploadDir = () => {
    return path.join(getBasePath(), 'public', 'uploads');
};

/**
 * 获取分片存储目录路径
 * @param {string} fileName - 文件名（不含扩展名）
 */
const getChunkDir = (fileName) => {
    return path.join(getBasePath(), 'public', 'chunkDir', fileName);
};

/**
 * 延迟函数
 * @param {number} time - 延迟毫秒数
 * @returns {Promise}
 */
const delayer = (time = 0) => {
    return new Promise(resolve => setTimeout(resolve, time));
};

// -------------------------- 全局状态管理 --------------------------
let stopUpload = {}; // 上传暂停状态管理

// -------------------------- 核心功能实现 --------------------------
/**
 * 整体文件上传（直接接收完整文件）
 */
const uploadWholeFile = async (ctx) => {
    try {
        const file = ctx.request.files.file;
        if (!file) {
            return sendResponse(ctx, 400, '未获取到文件', null);
        }

        const originalFileName = file.originalFilename;
        const uploadDir = getUploadDir();
        await fse.ensureDir(uploadDir);

        const finalFilePath = path.join(uploadDir, originalFileName);
        if (await fse.pathExists(finalFilePath)) {
            await fs.unlink(finalFilePath);
            console.log(`已覆盖旧文件: ${originalFileName}`);
        }

        await fse.move(file.filepath, finalFilePath, {overwrite: true});

        const responseData = {
            fileName: originalFileName,
            fileUrl: `http://${ip}:${PORT}/uploads/${originalFileName}`,
            localPath: finalFilePath,
            progress: 100
        };
        sendResponse(ctx, 200, '文件上传成功', responseData);
    } catch (error) {
        console.error('文件上传异常:', error);
        sendResponse(ctx, 500, error.message || '文件上传失败', null);
    }
};

/**
 * 文件上传处理（分片上传）
 */
/**
 * 文件上传处理（分片上传）
 */
const uploadFile = async (ctx) => {
    try {
        // 获取上传的文件分片
        const file = ctx.request.files.file;
        if (!file) {
            return sendResponse(ctx, 400, '未获取到文件', '未获取到文件');
        }

        // 解析文件名信息 [name, index, ext, chunkSize, totalSize]
        const [name, index, ext, chunkSize, totalSize] = file.originalFilename.split('.');
        const currentSize = Number(index) * Number(chunkSize);
        // 计算进度（处理最后一片可能超出总大小的情况）
        const progress = ((currentSize + Number(chunkSize)) >= Number(totalSize))
            ? 100
            : (currentSize / Number(totalSize) * 100).toFixed(2);

        // 初始化上传状态（第一片时）
        if (index === '0') {
            stopUpload[name] = false;
        }

        // 处理暂停逻辑
        if (stopUpload[name]) {
            const tempFilePath = path.join(file.filepath);
            // 异步删除临时文件（避免阻塞）
            await fs.unlink(tempFilePath).catch(err =>
                console.warn(`删除暂停的临时文件失败: ${err.message}`)
            );
            return sendResponse(ctx, 202, '上传已暂停', '上传已暂停', {progress});
        }

        // 准备分片存储目录
        const chunkDir = getChunkDir(name);
        await fse.ensureDir(chunkDir); // 递归创建目录（无需嵌套判断）

        // 移动分片到目标目录
        const chunkPath = path.join(chunkDir, `${name}${index}`);
        await fse.move(file.filepath, chunkPath, {overwrite: true});

        // 检查是否为最后一片，需要合并
        if (progress === 100) {
            const finalFileName = `${name}.${ext}`;
            const uploadDir = getUploadDir();
            const finalFilePath = path.join(uploadDir, finalFileName);

            // 确保上传目录存在
            await fse.ensureDir(uploadDir);

            // 如果目标文件已存在，先删除
            if (await fse.pathExists(finalFilePath)) {
                await fs.unlink(finalFilePath);
                console.log(`已删除已存在的旧文件: ${finalFileName}`);
            }

            // 读取所有分片并按序号排序
            const chunks = await fse.readdir(chunkDir);
            chunks.sort((a, b) => {
                // 提取分片序号进行排序（确保正确处理多位数序号）
                const numA = Number(a.replace(name, ''));
                const numB = Number(b.replace(name, ''));
                return numA - numB;
            });

            // 使用流合并文件（比appendFileSync更高效，尤其对大文件）
            const writeStream = fse.createWriteStream(finalFilePath);
            for (const chunk of chunks) {
                const chunkFilePath = path.join(chunkDir, chunk);
                const chunkBuffer = await fs.readFile(chunkFilePath);
                await new Promise(resolve => {
                    writeStream.write(chunkBuffer, resolve);
                });
                // 合并后删除分片（释放空间）
                await fs.unlink(chunkFilePath);
            }
            // 关闭流并删除分片目录
            writeStream.end();
            await fse.remove(chunkDir);
            return sendResponse(ctx, 200, '文件上传成功', '文件上传成功', {
                fileName: finalFileName,
                fileUrl: `http://${ip}:${PORT}/uploads/${finalFileName}`,
                localPath: finalFilePath,
                progress: progress,
                end: true
            });
        }

        // 非最后一片，返回当前进度
        return sendResponse(ctx, 200, '文件上传成功', '文件上传成功', {
            progress: progress
        });
    } catch (error) {
        console.error('文件上传异常:', error);
        sendResponse(ctx, 500, error.message || '上传失败', error.message || '上传失败');
    }
};

/**
 * 文件上传验证（检查是否已上传/需要续传）
 */
const verify = async (ctx) => {
    try {
        const {name} = ctx.request.body;
        if (!name) {
            return sendResponse(ctx, 400, '缺少文件名参数', '缺少文件名参数');
        }

        const fileName = name.split('.')[0];
        stopUpload[fileName] = false;

        const uploadDir = getUploadDir();
        const finalFilePath = path.join(uploadDir, name);
        if (await fse.pathExists(finalFilePath)) {
            return sendResponse(ctx, 200, '文件已存在，不需要重新上传', '文件已存在，不需要重新上传');
        }

        const chunkDir = getChunkDir(fileName);
        if (await fse.pathExists(chunkDir)) {
            const uploadedChunks = await fse.readdir(chunkDir);
            return sendResponse(ctx, 201, '该文件有部分上传数据', uploadedChunks);
        }

        sendResponse(ctx, 201, '文件未上传过', []);
    } catch (error) {
        console.error('文件验证异常:', error);
        sendResponse(ctx, 500, '验证失败', error.message || '验证失败');
    }
};

/**
 * 暂停文件上传
 */
const uploadPaused = async (ctx) => {
    try {
        const {name} = ctx.request.body;
        if (!name) {
            return sendResponse(ctx, 400, '缺少文件名参数', '缺少文件名参数');
        }

        const fileName = name.split('.')[0];
        if (stopUpload[fileName]) {
            return sendResponse(ctx, 200, '文件上传已暂停', '文件上传已暂停');
        } else {
            stopUpload[fileName] = true;
            return sendResponse(ctx, 200, '暂停上传成功', '暂停上传成功');
        }
    } catch (error) {
        console.error('暂停上传异常:', error);
        sendResponse(ctx, 500, '暂停操作失败', error.message || '暂停操作失败');
    }
};

/**
 * 获取文件列表（递归遍历目录）
 */
const getFiles = async (ctx) => {
    try {
        const basePath = getBasePath();
        const folderPath = path.join(basePath, 'public');

        const initFun = async (dirPath) => {
            const item = {
                name: path.basename(dirPath),
                children: [],
                type: 'folder',
                dirPath: dirPath
            };

            const entries = await fs.readdir(dirPath, {withFileTypes: true});
            for (const entry of entries) {
                const fullPath = path.join(dirPath, entry.name);
                const fileObj = {
                    name: entry.name,
                    dirPath: fullPath,
                    type: entry.isFile() ? 'file' : 'folder'
                };

                if (entry.isDirectory()) {
                    fileObj.children = (await initFun(fullPath)).children;
                }
                item.children.push(fileObj);
            }
            return item;
        };

        const rootFiles = await initFun(folderPath);
        rootFiles.name = "全部文件";

        sendResponse(ctx, 200, '获取文件成功', [rootFiles]);
    } catch (e) {
        console.error('获取文件列表异常:', e);
        sendResponse(ctx, 500, '获取文件失败', e.message || '获取文件失败');
    }
};

// -------------------------- 路由配置 --------------------------
const uploadRoutes = [
    {type: 'post', url: '/uploadFile', method: uploadFile},
    {type: 'post', url: '/uploadWholeFile', method: uploadWholeFile},
    {type: 'post', url: '/verify', method: verify},
    {type: 'post', url: '/uploadPaused', method: uploadPaused},
    {type: 'post', url: '/getFiles', method: getFiles},
];

module.exports = uploadRoutes;
